zeux's Normal Transformation
#Transform #行列 #CG #数学
Normal Matrixが唯一の法線を求める方法ではない
せん断を含まないTRSであれば、行列を使わずとも法線を変換できるよ
https://github.com/mrdoob/three.js/issues/18497#issuecomment-583771048
Three.jsのInstancingにおいて、Instance Matrixから法線を求めるのに使われている手法(2023年1月現在)
たぶんzeuxさんが初出ではないんだろうけど、便宜上zeuxさんの手法と呼びます
手法
$ {\bf N} = (({\bf R} {{\bf S})^T})^{-1}
$ (({\bf R} {{\bf S})^T})^{-1} = ({\bf S}^T {\bf R}^T)^{-1} = ({\bf R}^T)^{-1} ({\bf S}^T)^{-1}
ここで、$ {\bf R}は直交行列なので、
$ ({\bf R}^T)^{-1} = {\bf R}
また、$ {\bf S}は対角行列なので、
$ {\bf S}^T = {\bf S}
これらより、
$ ({\bf R}^T)^{-1} ({\bf S}^T)^{-1} = {\bf R}{\bf S}^{-1} = {\bf R}{\bf S} \ {\bf S}^{-1}{\bf S}^{-1}
ということで、以下のコードで法線を求めることができる:
code:glsl
vec3 m = mat3(modelMatrix);
vec3 transformedNormal = normal;
transformedNormal /= vec3(dot(m0, m0), dot(m1, m1), dot(m2, m2));
transformedNormal = normalize(m * transformedNormal);
Desmos
2次元でzeuxの手法を試してみたやつ
https://gyazo.com/98e358d6cbf32a7d46ab4850624f4851
https://www.desmos.com/calculator/zgmd9wcxoe